import java.util.ArrayList;

import javax.media.j3d.BranchGroup;
import javax.vecmath.Color3f;
import javax.vecmath.Vector2f;

public class ParticleManager {
	private ArrayList<Particle> particles;
	private float update_rate;
	
	BranchGroup scene;
	
	public ParticleManager(BranchGroup scene, float update_rate) {
		this.scene = scene;
		this.update_rate = update_rate;
		particles = new ArrayList<Particle>();
	}
	
	public void updateParticles() {
		for(int i = 0 ; i < particles.size() ; i++) {
			particles.get(i).updateState(1f / update_rate);
			particles.get(i).updateTransformGroup();
			if(particles.get(i).shouldDelete()) {
				scene.removeChild(particles.get(i).BG);
				particles.remove(i--);	
			}
		}
	}
	
	public void addThrusterParticles(Polygon ship) 
	{
		final int COUNT = 2; //particles to add every time this is called
		final float SPEED = 5; //how fast it should move
		final float SPREAD = (float)(Math.PI/8);
		
		final float redmin = 0.6f;
		final float greenmax = 0.6f;
		
		Vector2f dir = ship.getForward();
		dir.scale(-1f);
		
		for(int i = 0 ; i < COUNT ; i++) {
			
			float theta = (float)(Math.random() - 0.5) * SPREAD;
			Vector2f v = rotate(dir,theta);
			v.scale(SPEED);
			v.scaleAdd(0.5f, ship.velocity, v);
			
			Color3f color = new Color3f(redmin + (float)( (1f-redmin) * Math.random()),
					(float)(Math.random()) * greenmax, 0);
			Particle p = new Particle(ship.position.x, ship.position.y,
					v.x, v.y, color);
			
			particles.add(p);
			scene.addChild(p.BG);
		}
	}
	
	//when a bullet hits an asteroid
	public void addBulletAsteroidParticles(Polygon asteroid, Bullet bullet) {
		final int COUNT = 20 - asteroid.getGeneration()*5;
		final float SPEED = 5;
		final float SPREAD = (float)(Math.PI/4);
		
		Vector2f dir = bullet.velocity;
		dir.normalize();
		dir.scale(-1f);
		
		for(int i = 0 ; i < COUNT ; i++) {
			
			float theta = (float)(Math.random() - 0.5) * SPREAD;
			Vector2f v = rotate(dir,theta);
			v.scale(SPEED);
			v.scale(0.5f + (float)(Math.random()/2));
			v.scaleAdd(0.5f, asteroid.velocity, v);
			
			float sc = (float)Math.random();
			Color3f color = new Color3f(sc,sc,sc);
			Particle p = new Particle(bullet.position.x, bullet.position.y,
					v.x, v.y, color);
			
			particles.add(p);
			scene.addChild(p.BG);
		}
	}
	
	//when two asteroids collide
	public void addAsteroidAsteroidParticles(Polygon a1, Polygon a2, CollisionInfo info) {
		//average velocity
		Vector2f avg = new Vector2f();
		avg.x = (a1.velocity.x + a2.velocity.x)/2f;
		avg.y = (a1.velocity.y + a2.velocity.y)/2f;
		
		final int COUNT = 1;
		final float SPEED = (a1.velocity.length() + a2.velocity.length())/2f;
		final float SPREAD = (float)(2 * Math.PI);
		
		for(int i = 0 ; i < COUNT ; i++) {
			float theta = (float)(Math.random() - 0.5) * SPREAD;
			Vector2f v = rotate(new Vector2f(1,0), theta);
			v.scale(SPEED);
			v.scale(0.1f + (float)(9*Math.random()/10));
			v.scaleAdd(0.5f, avg);
			
			float sc = (float)Math.random();
			Color3f color = new Color3f(sc,sc,sc);
			Particle p = new Particle(info.position.x, info.position.y,
					v.x, v.y, color);
			
			particles.add(p);
			scene.addChild(p.BG);
		}
	}
	
	public void addAsteroidDestructionParticles(Polygon asteroid) {
		final int COUNT = 30 - asteroid.getGeneration()*5;
		final float SPEED = 3;
		final float SPREAD = (float)(2*Math.PI);
		
		for(int i = 0 ; i < COUNT ; i++) {
			float theta = (float)(Math.random() - 0.5) * SPREAD;
			Vector2f v = rotate(new Vector2f(1,0), theta);
			v.scale(SPEED);
			v.scale(0.1f + (float)(9*Math.random()/10));
			v.scaleAdd(0.5f, asteroid.velocity,v);
			
			float sc = (float)Math.random();
			Color3f color = new Color3f(sc,sc,sc);
			Particle p = new Particle(asteroid.position.x, asteroid.position.y,
					v.x, v.y, color);
			
			particles.add(p);
			scene.addChild(p.BG);
		}
	}
	
	public void addEnemyDestructionParticles(Polygon enemy) {
		final int COUNT = 50;
		final float SPEED = 4;
		final float SPREAD = (float)(2*Math.PI);
		
		Color3f enemy_color = new Color3f(0.5f,0.5f,1);
		final float redmin = 0.6f;
		final float greenmax = 0.6f;
		
		for(int i = 0 ; i < COUNT ; i++) {
			float theta = (float)(Math.random() - 0.5) * SPREAD;
			Vector2f v = rotate(new Vector2f(1,0), theta);
			v.scale(SPEED);
			v.scale(0.1f + (float)(9*Math.random()/10));
			v.scaleAdd(0.5f, enemy.velocity,v);
			
			Color3f color;
			if(Math.random() > 0.5)
				color = enemy_color;
			else
				color = new Color3f(redmin + (float)( (1f-redmin) * Math.random()),
						(float)(Math.random()) * greenmax, 0);

			Particle p = new Particle(enemy.position.x, enemy.position.y,
					v.x, v.y, color);
			
			particles.add(p);
			scene.addChild(p.BG);
		}
	}
	
	public void addShipDestructionParticles(Polygon ship) {
		final int COUNT = 100;
		final float SPEED = 4;
		final float SPREAD = (float)(2*Math.PI);
		
		Color3f ship_color = new Color3f(1f,1f,1f);
		final float redmin = 0.6f;
		final float greenmax = 0.6f;
		
		for(int i = 0 ; i < COUNT ; i++) {
			float theta = (float)(Math.random() - 0.5) * SPREAD;
			Vector2f v = rotate(new Vector2f(1,0), theta);
			v.scale(SPEED);
			v.scale(0.1f + (float)(9*Math.random()/10));
			v.scaleAdd(0.5f, ship.velocity,v);
			
			Color3f color;
			if(Math.random() > 0.5)
				color = ship_color;
			else
				color = new Color3f(redmin + (float)( (1f-redmin) * Math.random()),
						(float)(Math.random()) * greenmax, 0);

			Particle p = new Particle(ship.position.x, ship.position.y,
					v.x, v.y, color);
			
			particles.add(p);
			scene.addChild(p.BG);
		}
	}
	
	private Vector2f rotate(Vector2f init, float theta) {
		Vector2f val = new Vector2f();
		val.x = init.x * (float)Math.cos(theta) - init.y * (float)Math.sin(theta);
		val.y = init.x * (float)Math.sin(theta) + init.y * (float)Math.cos(theta);
		return val;
	}
}
